package com.ccteam.admin.viewmodels.banner

import android.app.Application
import androidx.lifecycle.*
import com.ccteam.admin.core.ADD_TYPE
import com.ccteam.admin.core.EDIT_TYPE
import com.ccteam.admin.repositories.BannerAdminRepository
import com.ccteam.admin.repositories.UploadAdminRepository
import com.ccteam.admin.utils.*
import com.ccteam.admin.view.bean.SelectInfoResult
import com.ccteam.admin.vo.Resource
import com.ccteam.model.banner.BannerDTO
import com.ccteam.model.banner.BannerNoIdDTO
import com.ccteam.model.banner.BannerVO
import com.ccteam.network.ApiError
import com.ccteam.network.exception.ApiException
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
 * @author Xiaoc
 * @since 2021/3/27
 */
@HiltViewModel
class BannerDetailViewModel @Inject constructor(
    application: Application,
    private val uploadFileUtils: UploadFileUtils,
    private val uploadRepository: UploadAdminRepository,
    private val bannerRepository: BannerAdminRepository,
    savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {

    /**
     * 轮播图图片地址是否成功
     */
    private val urlSuccess = MutableLiveData(false)

    /**
     * 轮播图类型ID是否成功
     */
    private val itemIdSuccess = MutableLiveData(false)

    /**
     * 轮播图类型是否成功
     */
    private val _itemTypeSuccess = MutableLiveData(false)
    val itemTypeSuccess: LiveData<Boolean> get() = _itemTypeSuccess

    /**
     * 当前是否能够开启编辑/新增按钮功能（需要输入条件均为true才能开启）
     */
    private val _editButtonEnable = MediatorLiveData<Boolean>()
    val editButtonEnable: LiveData<Boolean> get() = _editButtonEnable

    /**
     * 是否启用删除按钮（当满足条件时启用）
     */
    private val _deleteButtonEnable = MediatorLiveData<Boolean>()
    val deleteButtonEnable: LiveData<Boolean> get() = _deleteButtonEnable

    private val _itemSubtitle = MutableLiveData<String>()
    val itemSubtitle: LiveData<String> get() = _itemSubtitle

    val type: Int = savedStateHandle["bannerEditType"] ?: ADD_TYPE

    private val bannerId = MutableLiveData<String>()

    /**
     * 原始的轮播图信息
     */
    private var originBannerInfo: BannerEditInfo? = null

    /**
     * 修改中的轮播图信息
     */
    private val _bannerInfo = MediatorLiveData<BannerEditInfo>()
    val bannerInfo: LiveData<BannerEditInfo> get() = _bannerInfo


    /**
     * 编辑时的加载信息
     */
    private val _editLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val editLoadMessage: LiveData<Event<LoadMessage>> get() = _editLoadMessage

    /**
     * 删除时的加载信息
     */
    private val _deleteLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val deleteLoadMessage: LiveData<Event<LoadMessage>> get() = _deleteLoadMessage

    /**
     * 全局加载状态
     */
    private val _loadMessage = MutableLiveData<LoadMessage>(LoadMessage.NotLoading)
    val loadMessage: LiveData<LoadMessage> get() = _loadMessage

    init {
        _editButtonEnable.addSource(urlSuccess){
            _editButtonEnable.value = it && itemIdSuccess.value == true && itemTypeSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(itemIdSuccess){
            _editButtonEnable.value = it && urlSuccess.value == true && itemTypeSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(itemTypeSuccess){
            _editButtonEnable.value = it && itemIdSuccess.value == true && urlSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_editLoadMessage){
            val enable = itemTypeSuccess.value == true && itemIdSuccess.value == true && urlSuccess.value == true
                    && it.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_deleteLoadMessage){
            val enable = itemTypeSuccess.value == true && itemIdSuccess.value == true && urlSuccess.value == true
                    && it.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _bannerInfo.addSource(bannerId){
            refreshBannerInfo()
        }

        bannerId.setValueIfNew(savedStateHandle["bannerId"])

        if(type == ADD_TYPE){
            _bannerInfo.value = BannerEditInfo(null,null,null,null,null)
        }
    }

    /**
     * 设置轮播图图片地址
     */
    fun setBannerUrl(url: String){
        _bannerInfo.value?.url = url
    }

    /**
     * 设置轮播图地址成功与否
     */
    fun setUrlSuccess(isSuccess: Boolean){
        urlSuccess.value = isSuccess
    }

    /**
     * 设置轮播图类型
     */
    fun setBannerType(type: Int){
        _bannerInfo.value?.type = type
        updateBannerEditInfo()
    }

    /**
     * 设置轮播图类型成功与否
     */
    fun setBannerTypeSuccess(isSuccess: Boolean){
        _itemTypeSuccess.value = isSuccess
    }

    /**
     * 设置轮播图类型对应ID
     */
    fun setBannerItemId(item: SelectInfoResult?){
        _itemSubtitle.value = item?.selectTitle
        _bannerInfo.value?.itemId = item?.selectId
        updateBannerEditInfo()
    }

    /**
     * 设置轮播图类型对应ID成功与否
     */
    fun setBannerIdSuccess(isSuccess: Boolean){
        itemIdSuccess.value = isSuccess
    }

    /**
     * 更新编辑内容信息（提醒UI进行更新）
     */
    fun updateBannerEditInfo(){
        _bannerInfo.value = _bannerInfo.value
    }

    fun refreshBannerInfo(){
        bannerId.value?.let {

            _loadMessage.value = LoadMessage.Loading

            viewModelScope.launch {
                val result = bannerRepository.getBannerInfo(it)
                if(result is Resource.Success){
                    _loadMessage.value = LoadMessage.NotLoading

                    originBannerInfo = BannerEditInfo.bannerVoToBannerEditInfo(result.data)
                    _bannerInfo.value = BannerEditInfo.bannerVoToBannerEditInfo(result.data)

                    setBannerTypeSuccess(true)
                    setBannerIdSuccess(true)
                    _itemSubtitle.value = originBannerInfo?.itemId ?: ""
                } else {
                    _loadMessage.value = LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message))
                }
            }
        }
    }

    fun editOrAddBannerInfo(){
        if(_editButtonEnable.value != true || _bannerInfo.value == null){
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,"非法操作")))
            return
        }

        if(originBannerInfo == _bannerInfo.value){
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.unknownCode,"未做任何更改")))
            return
        }

        _editLoadMessage.value = Event(LoadMessage.Loading)

        /**
         * 上传前会检测头像是否为本地的头像，如果为本地头像
         * 则先上传获得文件地址后再更新内容
         */
        viewModelScope.launch(
            CoroutineExceptionHandler { c, throwable ->
                val errorMessage = if (throwable is ApiException) {
                    ErrorMessage(throwable.errorCode, throwable.message)
                } else {
                    ErrorMessage(ApiError.unknownCode, throwable.message)
                }
                _editLoadMessage.value = Event(LoadMessage.Error(errorMessage))
            }
        ) {
            uploadBannerPhoto(_bannerInfo.value?.url)

            val result = if(type == EDIT_TYPE){
                bannerRepository.editBannerInfo(_bannerInfo.value!!.toBannerDTO())
            } else {
                bannerRepository.createBannerInfo(_bannerInfo.value!!.toBannerNoIdDTO())
            }
            handleEditResult(result)
        }

    }

    /**
     * 上传歌手头像
     */
    private suspend fun uploadBannerPhoto(photoUri: String?) {
        val application = getApplication<Application>()

        if (photoUri?.startsWith("content://") == false) {
            setBannerUrl(photoUri)
            return
        }

        val result = uploadRepository.getImageToken()
        // 检测token是否获取成功
        if (result !is Resource.Success || result.data.isNullOrEmpty()) {
            throw ApiException(ApiError.serverErrorCode, "获取Token失败")
        }
        val token = result.data

        suspendCoroutine<String> { cn ->
            viewModelScope.launch{
                uploadFileUtils.upload(application, token, photoUri, { }, { fileUrl ->
                    setBannerUrl(fileUrl)
                    cn.resume(fileUrl)
                }, { errorMessage ->
                    cn.resumeWithException(ApiException(ApiError.serverErrorCode, errorMessage))
                })
            }
        }

    }

    fun deleteBannerInfo(){
        _deleteLoadMessage.value = Event(LoadMessage.Loading)

        bannerId.value?.let {
            viewModelScope.launch {
                val result = bannerRepository.deleteBannerInfo(it)
                handleDeleteResult(result)
            }
        }
    }

    private fun handleEditResult(result: Resource<Nothing?>){
        if(result is Resource.Success){
            _editLoadMessage.value = Event(LoadMessage.Success)
        } else{
            _editLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message)))
        }
    }

    private fun handleDeleteResult(result: Resource<Nothing?>){
        if(result is Resource.Success){
            _deleteLoadMessage.value = Event(LoadMessage.Success)
        } else{
            _deleteLoadMessage.value = Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode,result.message)))
        }
    }

    data class BannerEditInfo(
        val id: String?,
        var isShow: Int?,
        var itemId: String?,
        var type: Int?,
        var url: String?
    ){
        companion object{
            fun bannerVoToBannerEditInfo(bannerVO: BannerVO?): BannerEditInfo{
                return BannerEditInfo(bannerVO?.id,bannerVO?.isShow,bannerVO?.itemId,bannerVO?.type,bannerVO?.url)
            }
        }

        fun toBannerDTO(): BannerDTO {
            return BannerDTO(id!!,isShow!!,itemId!!,type!!,url!!)
        }

        fun toBannerNoIdDTO(): BannerNoIdDTO {
            return BannerNoIdDTO(1,itemId!!,type!!,url!!)
        }
    }
}